﻿
Imports osi.root.constants
Imports osi.root.formation
Imports osi.root.procedure
Imports osi.root.utils
Imports osi.root.lock
Imports osi.root.threadpool

Partial Public Class device_pool(Of T)
    Protected Sub begin_close_device(ByVal c As T)
        'may use async_sync to close the device
        'so there is possibility a deadlock
        'async_sync is locking current thread, while no other thread to run the real close procedure
        'ps. closing device should not block the follow-up procedure, such as creating device,
        'so queue the closing procedure into managed threadpool is not a bad idea
        'the only problem is, if the managed threadpool does not have enough threads to handle the request,
        'the closing may be delayed, and cause the resource exhausted trouble
        'FIXME: find a better solution
        If in_iqless_threadpool_thread() Then
            queue_in_managed_threadpool(Sub()
                                            close_device(c)
                                            'the inherited close_device function may not really close the device
                                            'so do not assert here
                                            'but the close_device may be delayed, so keepalive
                                            GC.KeepAlive(c)
                                        End Sub)
        Else
            close_device(c)
        End If
    End Sub

    Protected Overloads Sub close_existing_devices(ByVal q As qless2(Of T))
        assert(Not q Is Nothing)
        While total_count() > uint32_0
            Dim c As T = Nothing
            Dim r As UInt32 = 0
            While q.pop(c) AndAlso assert(Not c Is Nothing)
                begin_close_device(c)
                r += uint32_1
            End While
            decrease_total_count(r)
            timeslice_sleep_wait_when(Function() q.empty() AndAlso total_count() > 0)
        End While
        assert(q.empty())
    End Sub

    Protected Function create_valid_device(ByVal p As pointer(Of T)) As event_comb
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  p.renew()
                                  ec = create_device(p)
                                  Return waitfor(ec) AndAlso
                                         goto_next()
                              End Function,
                              Function() As Boolean
                                  Return ec.end_result() AndAlso
                                         is_valid_device(+p) AndAlso
                                         goto_end()
                              End Function)
    End Function

    Protected Function create_new_device(ByVal p As pointer(Of T)) As event_comb
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  If increase_total_count() Then
                                      ec = create_valid_device(p)
                                      Return waitfor(ec) AndAlso
                                             goto_next()
                                  Else
                                      Return False
                                  End If
                              End Function,
                              Function() As Boolean
                                  If ec.end_result() Then
                                      Return goto_end()
                                  Else
                                      decrease_total_count()
                                      Return False
                                  End If
                              End Function)
    End Function

    Protected Sub close_existing_device(ByVal c As T)
        begin_close_device(c)
        decrease_total_count()
    End Sub

    Protected Function sync_get(ByRef r As T) As Boolean
        If expired() Then
            Return False
        Else
            While sync_get_device(r)
                If is_valid_device(r) Then
                    Return True
                Else
                    assert(Not release(r))
                End If
            End While
            Return False
        End If
    End Function

    Protected Function release(ByVal c As T) As Boolean
        If is_valid_device(c) AndAlso
           release_device(c) Then
            Return True
        Else
            close_existing_device(c)
            Return False
        End If
    End Function

    Protected Function [get](ByVal r As pointer(Of T)) As event_comb
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  If expired() Then
                                      Return False
                                  Else
                                      r.renew()
                                      ec = get_device(r)
                                      Return waitfor(ec) AndAlso
                                             goto_next()
                                  End If
                              End Function,
                              Function() As Boolean
                                  If ec.end_result() Then
                                      If is_valid_device(+r) Then
                                          Return goto_end()
                                      Else
                                          Return goto_begin()
                                      End If
                                  Else
                                      Return False
                                  End If
                              End Function)
    End Function
End Class
